﻿using Microsoft.EntityFrameworkCore.Storage;
using Sgr.Domain.Uow;
using Sgr.EntityFrameworkCore;
using Sgr.Exceptions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using MediatR;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.Extensions.Logging;

namespace Sgr.Domain.Uow
{
    /// <summary>
    /// DbContext提供者的工作单元实现
    /// </summary>
    /// <typeparam name="TDbContext">DbContext类型</typeparam>
    /// <remarks>
    /// 该类负责：
    /// 1. 在工作单元中管理DbContext的生命周期
    /// 2. 处理数据库事务的创建和共享
    /// 3. 确保DbContext的正确初始化和配置
    /// </remarks>
    public class UnitOfWorkDbContextProvider<TDbContext>
        : IDbContextProvider<TDbContext> where TDbContext : UnitOfWorkDbContext
    {
        private readonly IUnitOfWorkManager _unitOfWorkManager;
        private readonly IMediator _mediator;

        /// <summary>
        /// 初始化DbContext提供者
        /// </summary>
        /// <param name="unitOfWorkManager">工作单元管理器</param>
        /// <param name="mediator"></param>
        public UnitOfWorkDbContextProvider(IUnitOfWorkManager unitOfWorkManager, IMediator mediator)
        {
            _unitOfWorkManager = unitOfWorkManager ??
                throw new ArgumentNullException(nameof(unitOfWorkManager));
            _mediator = mediator ??
                throw new ArgumentNullException(nameof(mediator));
        }

        /// <summary>
        /// 获取DbContext实例
        /// </summary>
        /// <remarks>
        /// 该方法确保：
        /// 1. DbContext在工作单元中创建和管理
        /// 2. 正确处理数据库事务
        /// 3. 维护DbContext的生命周期
        /// </remarks>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>已初始化的DbContext实例</returns>
        /// <exception cref="BusinessException">当不在工作单元中或事务配置错误时抛出</exception>
        public virtual async Task<TDbContext> GetDbContextAsync(CancellationToken cancellationToken = default)
        {
            // 确保在工作单元中
            var unitOfWork = _unitOfWorkManager.Current
                ?? throw new BusinessException("只能在一个工作单元内创建TDbContext!");

            // 获取DbContext实例
            var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
            string dbContextKey = $"EfCore_{dbContext.ContextId.InstanceId}";

            var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
            if (databaseApi == null)
            {
                dbContext.Initialize(unitOfWork.Options);

                //var mediator = unitOfWork.ServiceProvider.GetRequiredService<IMediator>();
                //databaseApi = new EfCoreDatabaseApi(dbContext, mediator);
                databaseApi = new EfCoreDatabaseApi(dbContext, _mediator);
                unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);

                // 如果需要，配置事务
                if (unitOfWork.Options.IsTransactional)
                {
                    await ConfigureTransactionAsync(dbContext, unitOfWork, dbContextKey, cancellationToken);
                }
            }

            return dbContext;
        }

        /// <summary>
        /// 配置数据库事务
        /// </summary>
        protected virtual async Task ConfigureTransactionAsync(TDbContext dbContext, IUnitOfWork unitOfWork, string dbContextKey, CancellationToken cancellationToken = default)
        {
            // 使用 is 模式匹配简化类型转换和判断
            if (unitOfWork.FindTransactionApi(dbContextKey) is not EfCoreTransactionApi activeTransaction)
            {
                // 创建新事务
                var dbTransaction = await CreateNewTransactionAsync(dbContext, unitOfWork, cancellationToken);
                unitOfWork.AddTransactionApi(
                    dbContextKey,
                    new EfCoreTransactionApi(dbTransaction, unitOfWork.Options.Timeout));
                return;
            }

            // 使用现有事务
            UseExistingTransaction(dbContext, activeTransaction);
        }

        /// <summary>
        /// 创建新的数据库事务
        /// </summary>
        protected virtual async Task<IDbContextTransaction> CreateNewTransactionAsync(
            TDbContext dbContext,
            IUnitOfWork unitOfWork,
            CancellationToken cancellationToken = default)
        {
            //using var cts = new CancellationTokenSource(
            //          TimeSpan.FromMilliseconds(unitOfWork.Options.Timeout ?? 30000));

            return unitOfWork.Options.IsolationLevel.HasValue
                ? await dbContext.Database.BeginTransactionAsync(
                    unitOfWork.Options.IsolationLevel.Value,
                    cancellationToken)
                : await dbContext.Database.BeginTransactionAsync(
                    cancellationToken);
        }

        /// <summary>
        /// 使用现有的数据库事务
        /// </summary>
        protected virtual void UseExistingTransaction(
            TDbContext dbContext,
            EfCoreTransactionApi activeTransaction)
        {
            // 使用模式匹配判断连接是否匹配
            if (dbContext.Database.GetDbConnection() is { } connection &&
                connection != activeTransaction.DbContextTransaction.GetDbTransaction().Connection)
            {
                throw new BusinessException(
                    "当前DbContext已经关联了一个事务，但当前DbContext的连接与事务的连接不一致！");
            }

            // 使用现有事务
            dbContext.Database.UseTransaction(activeTransaction.DbContextTransaction.GetDbTransaction());
        }
    }
}